﻿using System;

using System.Runtime.InteropServices;
using System.IO;
using StackExchange.Redis;
using System.Text;
using System.Collections;

namespace FaceCapture
{
    
    public class AlertManage
    {
        public static ConnectionMultiplexer redisClient = ConnectionMultiplexer.Connect("localhost");
        private Int32[] m_lAlarmHandle = new Int32[200];
        private Int32 iListenHandle = -1;
        private uint iLastErr = 0;
        private string strErr;

        public CHCNetSDK.LOGINRESULTCALLBACK LoginCallBack = null;
        private CHCNetSDK.EXCEPYIONCALLBACK m_fExceptionCB = null;
        private CHCNetSDK.MSGCallBack_V31 m_falarmData_V31 = null;
        private CHCNetSDK.MSGCallBack m_falarmData = null;

        public delegate void UpdateTextStatusCallback(string strLogStatus, IntPtr lpDeviceInfo);
        public delegate void UpdateListBoxCallback(string strAlarmTime, string strDevIP, string strAlarmMsg);
        public delegate void UpdateListBoxCallbackException(string strAlarmTime, int lUserID, string strAlarmMsg);
        private string ip = "";
        private string today = "";
        public static string faceDir = "";
        public static string backgroundDir = "";

        public AlertManage()
        {
            bool m_bInitSDK = CHCNetSDK.NET_DVR_Init();


            if (m_bInitSDK == false)
            {
                Console.WriteLine("NET_DVR_Init error!");
                return;
            }
            else
            {
                byte[] strIP = new byte[16 * 16];
                uint dwValidNum = 0;
                Boolean bEnableBind = false;

                //获取本地PC网卡IP信息
                if (CHCNetSDK.NET_DVR_GetLocalIP(strIP, ref dwValidNum, ref bEnableBind))
                {
                    if (dwValidNum > 0)
                    {
                        //取第一张网卡的IP地址为默认监听端口
                        this.ip = System.Text.Encoding.UTF8.GetString(strIP, 0, 16);
                        //CHCNetSDK.NET_DVR_SetValidIP(0,true); //绑定第一张网卡
                    }

                }

                //保存SDK日志 To save the SDK log
                CHCNetSDK.NET_DVR_SetLogToFile(3, Configs.logDir, true);

                //设置透传报警信息类型
                CHCNetSDK.NET_DVR_LOCAL_GENERAL_CFG struLocalCfg = new CHCNetSDK.NET_DVR_LOCAL_GENERAL_CFG();
                struLocalCfg.byAlarmJsonPictureSeparate = 1;//控制JSON透传报警数据和图片是否分离，0-不分离(COMM_VCA_ALARM返回)，1-分离（分离后走COMM_ISAPI_ALARM回调返回）

                Int32 nSize = Marshal.SizeOf(struLocalCfg);
                IntPtr ptrLocalCfg = Marshal.AllocHGlobal(nSize);
                Marshal.StructureToPtr(struLocalCfg, ptrLocalCfg, false);

                if (!CHCNetSDK.NET_DVR_SetSDKLocalCfg(17, ptrLocalCfg))  //NET_DVR_LOCAL_CFG_TYPE_GENERAL
                {
                    iLastErr = CHCNetSDK.NET_DVR_GetLastError();
                    strErr = "NET_DVR_SetSDKLocalCfg failed, error code= " + iLastErr;
                    Console.WriteLine(strErr);
                }
                Marshal.FreeHGlobal(ptrLocalCfg);

                for (int i = 0; i < 200; i++)
                {
                    m_lAlarmHandle[i] = -1;
                }

                //设置异常消息回调函数
                if (m_fExceptionCB == null)
                {
                    m_fExceptionCB = new CHCNetSDK.EXCEPYIONCALLBACK(cbExceptionCB);
                }
                CHCNetSDK.NET_DVR_SetExceptionCallBack_V30(0, IntPtr.Zero, m_fExceptionCB, IntPtr.Zero);


                //设置报警回调函数
                if (m_falarmData_V31 == null)
                {
                    m_falarmData_V31 = new CHCNetSDK.MSGCallBack_V31(MsgCallback_V31);
                }
                CHCNetSDK.NET_DVR_SetDVRMessageCallBack_V31(m_falarmData_V31, IntPtr.Zero);
            }
        }

        public void cbExceptionCB(uint dwType, int lUserID, int lHandle, IntPtr pUser)
        {
            //异常消息信息类型
            string stringAlarm = "异常消息回调，信息类型：0x" + Convert.ToString(dwType, 16) + ", lUserID:" + lUserID + ", lHandle:" + lHandle;
        }

        public bool MsgCallback_V31(int lCommand, ref CHCNetSDK.NET_DVR_ALARMER pAlarmer, IntPtr pAlarmInfo, uint dwBufLen, IntPtr pUser)
        {
            //通过lCommand来判断接收到的报警信息类型，不同的lCommand对应不同的pAlarmInfo内容
            AlarmMessageHandle(lCommand, ref pAlarmer, pAlarmInfo, dwBufLen, pUser);

            return true; //回调函数需要有返回，表示正常接收到数据
        }

        public void MsgCallback(int lCommand, ref CHCNetSDK.NET_DVR_ALARMER pAlarmer, IntPtr pAlarmInfo, uint dwBufLen, IntPtr pUser)
        {
            //通过lCommand来判断接收到的报警信息类型，不同的lCommand对应不同的pAlarmInfo内容
            AlarmMessageHandle(lCommand, ref pAlarmer, pAlarmInfo, dwBufLen, pUser);
        }

        public void AlarmMessageHandle(int lCommand, ref CHCNetSDK.NET_DVR_ALARMER pAlarmer, IntPtr pAlarmInfo, uint dwBufLen, IntPtr pUser)
        {
            if (lCommand == CHCNetSDK.COMM_ISAPI_ALARM)
            {
                this.CheckForder();
                ProcessCommAlarm_ISAPIAlarm(ref pAlarmer, pAlarmInfo, dwBufLen, pUser);
            }
        }

        public string GetTimeStamp()
        {
            TimeSpan ts = DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 0, 0);
            return Convert.ToInt64(ts.TotalSeconds).ToString();
        }

        private void ProcessCommAlarm_ISAPIAlarm(ref CHCNetSDK.NET_DVR_ALARMER pAlarmer, IntPtr pAlarmInfo, uint dwBufLen, IntPtr pUser)
        {
            try {
                CHCNetSDK.NET_DVR_ALARM_ISAPI_INFO struISAPIAlarm = new CHCNetSDK.NET_DVR_ALARM_ISAPI_INFO();
                uint dwSize = (uint)Marshal.SizeOf(struISAPIAlarm);
                struISAPIAlarm = (CHCNetSDK.NET_DVR_ALARM_ISAPI_INFO)Marshal.PtrToStructure(pAlarmInfo, typeof(CHCNetSDK.NET_DVR_ALARM_ISAPI_INFO));

                if (struISAPIAlarm.byPicturesNumber == 0)
                {
                    return;
                }

                //报警设备IP地址
                string strIP = System.Text.Encoding.UTF8.GetString(pAlarmer.sDeviceIP).TrimEnd('\0');

                IDatabase db = redisClient.GetDatabase();
                //RedisValue[] rvs = new RedisValue[struISAPIAlarm.byPicturesNumber];

                var totalImageNum = struISAPIAlarm.byPicturesNumber;



                var filePaths = new ArrayList();

                var canSaveBackgroundPic = false;// 是否保存背景图片(设置默认不保存背景图片)
                for (int i = 0; i < totalImageNum; i++)
                {
                    CHCNetSDK.NET_DVR_ALARM_ISAPI_PICDATA struPicData = new CHCNetSDK.NET_DVR_ALARM_ISAPI_PICDATA();
                    struPicData.szFilename = new byte[256];
                    Int32 nSize = Marshal.SizeOf(struPicData);
                    struPicData = (CHCNetSDK.NET_DVR_ALARM_ISAPI_PICDATA)Marshal.PtrToStructure((IntPtr)((Int64)(struISAPIAlarm.pPicPackData) + i * nSize), typeof(CHCNetSDK.NET_DVR_ALARM_ISAPI_PICDATA));

                    //保存图片数据
                    if ((struPicData.dwPicLen != 0) && (struPicData.pPicData != IntPtr.Zero))
                    {
                        int iLen = (int)struPicData.dwPicLen;
                        if (iLen < 6144) //小于6k的图片不要
                        {
                            continue;
                        }
                        var fpath = "";

                        // 背景图片
                        if (i>0 && i== totalImageNum-1)
                        {
                            if (!canSaveBackgroundPic)
                            {
                                continue; // 如果不保存背景图片,跳过
                            }

                            fpath = AlertManage.backgroundDir + i + "_" + strIP + "_" + this.GetTimeStamp() + ".jpg";                            
                        }
                        else
                        {
                            //人像
                            fpath = AlertManage.faceDir + i + "_" + strIP + "_" + this.GetTimeStamp() + ".jpg";
                            canSaveBackgroundPic = true;
                        }

                        FileStream fs = new FileStream(fpath, FileMode.Create);

                        byte[] by = new byte[iLen];
                        Marshal.Copy(struPicData.pPicData, by, 0, iLen);
                        fs.Write(by, 0, iLen);
                        fs.Close();

                        filePaths.Add(fpath);
                    }
                }

                if (filePaths.Count > 0)
                {
                    var filePathStr = string.Join("|", filePaths.ToArray());
                    Console.WriteLine(filePathStr);
                    db.ListRightPush("local-center-fer-list", new RedisValue(filePathStr));
                }
                
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
            
        }


        public void startListen()
        {

            if (m_falarmData == null)
            {
                m_falarmData = new CHCNetSDK.MSGCallBack(MsgCallback);
            }

            iListenHandle = CHCNetSDK.NET_DVR_StartListen_V30(this.ip, 7200, m_falarmData, IntPtr.Zero);
            if (iListenHandle < 0)
            {
                iLastErr = CHCNetSDK.NET_DVR_GetLastError();
                strErr = "启动监听失败，错误号：" + iLastErr; //撤防失败，输出错误号
                Console.WriteLine(strErr);
            }

        }

        public void CheckForder()
        {
            var now = DateTime.Now.ToString("yyyyMMdd");
            if (this.today == now)
            {
                return;
            }

            AlertManage.faceDir = Configs.faceImgDir+ now + "_face\\";
            AlertManage.backgroundDir = Configs.faceImgDir + now + "_baks\\";

            if (!Directory.Exists(AlertManage.faceDir))
            {
                Directory.CreateDirectory(AlertManage.faceDir);
            }

            if (!Directory.Exists(AlertManage.backgroundDir))
            {
                Directory.CreateDirectory(AlertManage.backgroundDir);
            }

            this.today = now;
        }
    }
}
